#ifndef __EPSILON_3D__CAMERA_H__
#define __EPSILON_3D__CAMERA_H__

#include "../Epsilon/Epsilon3D/matrix.h"

//class eInput;

#include "input.h"

class e3dCamera : public eInput_iListener
{
public:
  e3dCamera (void);

  void Update (eInput* input); // Update
  void Move   (eInput* input); // Move the camera's eye
  void Rotate (eInput* input); // Rotate the view

  void       SetPos (float x, float y, float z);
  e3dVector3 GetPos (void);

  float*     GetModelview (void) { return &m_matView.m11; };

  inline e3dVector3 right_vec (void) const {
    return e3dVector3 (m_matView [0], m_matView [4], m_matView [8]);
  }
  inline e3dVector3 right_level_vec (void) const {
    return e3dVector3 (m_matView [0], m_matView [4], 0.0f);
  }
  inline e3dVector3 fwd_vec (void) const {
    return e3dVector3 (m_matView [2], m_matView [6], m_matView [10]);
  }
  inline e3dVector3 fwd_level_vec (void) const {
    return e3dVector3 (m_matView [2], m_matView [6], 0.0f);
  }
  inline e3dVector3 up_vec (void) const {
    return e3dVector3 (m_matView [1], m_matView [5], m_matView [9]);
  }
  inline e3dVector3 up_level_vec (void) const {
    return e3dVector3 (m_matView [1], m_matView [5], 0.0f);
  }

  /* TEMP */
  e3dVector3 GetEye  (void) { return m_vEye;  };
  e3dVector3 GetLook (void) { return m_vLook; };
  e3dVector3 GetUp   (void) { return m_vUp;   };

  void       SetRot (float angle);

  /// If m_bDeferred is true, then this will apply pending
  ///   transformations.
  void       FlushPendingTransforms (void);

  /* Handle mouselook... */
  void OnMouse      (Epsilon::Mouse state, Epsilon::Mouse last);

private:
  e3dVector3   m_vEye,  // Eye Position
               m_vLook, // Look Vector
               m_vUp;   // Up Vector

  e3dVector3   m_vDirection;
  e3dVector3   m_vRotAxis;

  bool         m_bDeferred;
  bool         m_bMouselook;

  float        x_rot;
  float        y_rot;

  float        m_fSpeed;

  e3dMatrix4x4 m_matView; // View matrix
};

#endif /* __EPSILON_3D__CAMERA_H__ */
